package edu.towson.cosc716.tests;


import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.junit.Before;
import org.junit.Test;

import edu.towson.cosc716.exceptions.MenuException;
import edu.towson.cosc716.gui.SimulationMoniter;
import edu.towson.cosc716.models.Constants;
import edu.towson.cosc716.models.DiningRoom;
import edu.towson.cosc716.models.InformationAggregator;
import edu.towson.cosc716.models.Invoker;
import edu.towson.cosc716.models.Menu;
import edu.towson.cosc716.models.MenuItem;
import edu.towson.cosc716.models.Table;
import junit.framework.TestCase;

// TODO: Auto-generated Javadoc
/**
 * The Class InvokerTest.
 */
public class InvokerTest extends ParentTest {
	
	/**
	 * Setup.
	 *
	 * @throws Exception the exception
	 */
	public void setup() throws Exception {
		super.setUp();
	}
	
	/**
	 * Test invoker get menu no filter.
	 *
	 * @throws Exception the exception
	 */
	@Test
	public void testInvokerGetMenuNoFilter() throws Exception {
		String requestedOperation = Constants.Operations.GET_MENU;
		List<Object> arguments = new ArrayList<Object>();
		String filterType = null;
		String parameter = null;
		arguments.add(filterType);
		arguments.add(parameter);
		Iterator result = (Iterator)invoker.processRequest(requestedOperation, arguments);
	
		int counter = 0;
		while (result.hasNext()) {
			result.next();
			counter++;
		}
		
		assertEquals(10, counter);
	}
	
	/**
	 * Test invoker get menu price filter.
	 *
	 * @throws Exception the exception
	 */
	@Test
	public void testInvokerGetMenuPriceFilter() throws Exception {
		String requestedOperation = Constants.Operations.GET_MENU;
		List<Object> arguments = new ArrayList<Object>();
		String filterType = Constants.MenuFilters.GET_MENU_BY_PRICE;
		String parameter = "10.00";
		arguments.add(filterType);
		arguments.add(parameter);
		Iterator result = (Iterator)invoker.processRequest(requestedOperation, arguments);
	
		int counter = 0;
		while (result.hasNext()) {
			result.next();
			counter++;
		}
		
		assertEquals(7, counter);
	}
	
	/**
	 * Test invoker get menu ratings filter.
	 *
	 * @throws Exception the exception
	 */
	@Test
	public void testInvokerGetMenuRatingsFilter() throws Exception {
		String requestedOperation = Constants.Operations.GET_MENU;
		List<Object> arguments = new ArrayList<Object>();
		String filterType = Constants.MenuFilters.GET_MENU_BY_RATING;
		String parameter = "3";
		arguments.add(filterType);
		arguments.add(parameter);
		Iterator result = (Iterator)invoker.processRequest(requestedOperation, arguments);
	
		int counter = 0;
		while (result.hasNext()) {
			result.next();
			counter++;
		}
		
		assertEquals(6, counter);
	}
	
	/**
	 * Test invoker get menu by type filter.
	 *
	 * @throws Exception the exception
	 */
	@Test
	public void testInvokerGetMenuByTypeFilter() throws Exception {
		String requestedOperation = Constants.Operations.GET_MENU;
		List<Object> arguments = new ArrayList<Object>();
		String filterType = Constants.MenuFilters.GET_MENU_BY_TYPE;
		String parameter = "Entree";
		arguments.add(filterType);
		arguments.add(parameter);
		Iterator result = (Iterator)invoker.processRequest(requestedOperation, arguments);
	
		int counter = 0;
		while (result.hasNext()) {
			result.next();
			counter++;
		}
		
		assertEquals(3, counter);
	}
	
	/**
	 * Test invoker get menu no filter bad parameter.
	 */
	@Test
	public void testInvokerGetMenuNoFilterBadParameter() {
		String requestedOperation = Constants.Operations.GET_MENU;
		List<Object> arguments = new ArrayList<Object>();
		String filterType = null;
		String parameter = "Text";
		arguments.add(filterType);
		arguments.add(parameter);
		try {
			Iterator result = (Iterator)invoker.processRequest(requestedOperation, arguments);
		} catch (Exception e) {
			assertEquals(Constants.ExceptionMessages.GET_MENU_FULL_BAD_PARAMATER, e.getMessage());
		}
	}
	
	/**
	 * Test invoker request table.
	 *
	 * @throws Exception the exception
	 */
	public void testInvokerRequestTable() throws Exception {
		String requestedOperation = Constants.Operations.REQUEST_TABLE;
		List<Object> arguments = new ArrayList<Object>();
		String partyName = "Smith";
		int partyCount = 4;
		arguments.add(partyName);
		arguments.add(partyCount);
		List<Object> results = (List<Object>) invoker.processRequest(requestedOperation, arguments);
		assertEquals(Constants.ReturnCodes.TABLE_REQUEST_AVAILABLE,results.get(0));
		int tableId = (Integer) results.get(1);
		assertTrue(( tableId > 0));
	}
	
	/**
	 * Test invoker request table full dining room.
	 *
	 * @throws Exception the exception
	 */
	public void testInvokerRequestTableFullDiningRoom() throws Exception {
		String requestedOperation = Constants.Operations.REQUEST_TABLE;
		List<Object> arguments = new ArrayList<Object>();
		String partyName = "Smith";
		int partyCount = 4;
		arguments.add(partyName);
		arguments.add(partyCount);
		List<Object> results = null;
		for (int i = 0; i < 10; i++) {
			results = (List<Object>) invoker.processRequest(requestedOperation, arguments);	
		}
		assertEquals(Constants.ReturnCodes.TABLE_REQUEST_NOT_AVAILABLE,results.get(0));
		int waitTime = (Integer) results.get(1);
		assertTrue(( waitTime == 15));
	}
	
	/**
	 * Test invoker place order.
	 *
	 * @throws Exception the exception
	 */
	public void testInvokerPlaceOrder() throws Exception {
		String requestedOperation = Constants.Operations.REQUEST_TABLE;
		List<Object> arguments = new ArrayList<Object>();
		String partyName = "Smith";
		int partyCount = 4;
		arguments.add(partyName);
		arguments.add(partyCount);
		List<Object> results = null;
		Table table = null;
		results = (List<Object>) invoker.processRequest(requestedOperation, arguments);
		if (results.get(0).equals(Constants.ReturnCodes.TABLE_REQUEST_AVAILABLE)) {
			table = informationAggregator.diningRoom.find((Integer)results.get(1));
		}
		assertNotNull(table);
		requestedOperation = Constants.Operations.PLACE_ORDER;
		arguments = new ArrayList<Object>();
		Iterator iterator = informationAggregator.menu.getMenu();
		MenuItem menuItem = null;
		while(iterator.hasNext()) {
			menuItem = (MenuItem)iterator.next();
			break;
		}
		Object result;
		arguments.add(menuItem.getItemId());
		arguments.add(table.getTableId());
		result = invoker.processRequest(requestedOperation, arguments);
		assertNotNull(result);
	}
	
	// Need to add more testing of placeOrder.
	
	/**
	 * Test invoker next kitchen order.
	 *
	 * @throws Exception the exception
	 */
	public void testInvokerNextKitchenOrder() throws Exception {
		String requestedOperation = Constants.Operations.NEXT_KITCHEN_QUEUE_MENU_ITEM;
		List<Object> arguments = new ArrayList<Object>();
		Object result = invoker.processRequest(requestedOperation, arguments);
		assertNotNull(result);
		
	}
	
	/**
	 * Test invoker next kitchen order til empty.
	 */
	public void testInvokerNextKitchenOrderTilEmpty() {
		String requestedOperation = Constants.Operations.NEXT_KITCHEN_QUEUE_MENU_ITEM;
		List<Object> arguments = new ArrayList<Object>();
		NoSuchElementException eTest = new NoSuchElementException();
		try {
			while (true) {
				Object result = invoker.processRequest(requestedOperation, arguments);
			}
		} catch (Exception e) {
			assertEquals(eTest.toString(), e.toString());
		}
		
	}
	
	/**
	 * Test invoker clear table.
	 *
	 * @throws Exception the exception
	 */
	public void testInvokerClearTable() throws Exception {
		String requestedOperation = Constants.Operations.REQUEST_TABLE;
		List<Object> arguments = new ArrayList<Object>();
		String partyName = "Smith";
		int partyCount = 4;
		arguments.add(partyName);
		arguments.add(partyCount);
		List<Object> results = null;
		for (int i = 0; i < 9; i++) {
			results = (List<Object>) invoker.processRequest(requestedOperation, arguments);	
		}
		requestedOperation = Constants.Operations.SET_TABLE_CLEAR;
		Enumeration tables = informationAggregator.diningRoom.getAllTables();
		List<Table> occupiedTables = new ArrayList<Table>();
		while (tables.hasMoreElements()) {
			Table table = (Table)tables.nextElement();
			if (table.isOccupied()) {
				occupiedTables.add(table);
			}
		}
		for (int i = 0; i < occupiedTables.size(); i++) {
			arguments = new ArrayList<Object>();
			arguments.add(occupiedTables.get(i).getTableId());
			Object result = invoker.processRequest(requestedOperation, arguments);
			assertNotNull(result);
		}
		
	}

}
